/**
 * 前端 WebSocket 通信模块
 * 用于与 Godot 实例进行 WebSocket 通信
 * 采用事件驱动设计模式
 */
class GodotWebSocketClient {
  constructor() {
    if (GodotWebSocketClient.instance) {
      return GodotWebSocketClient.instance;
    }

    this.ws = null;
    this.isConnected = false;
    this.reconnectAttempts = 0;
    this.maxReconnectAttempts = 5;
    this.reconnectInterval = 3000; // 3秒

    // 事件监听器存储
    this.eventListeners = new Map();

    // 连接配置
    this.config = {
      serverUrl:
        import.meta.env.VITE_WS_HOST + import.meta.env.VITE_WS_PORT ||
        "ws://localhost:8080",
      godotId: null,
      autoReconnect: true,
    };

    GodotWebSocketClient.instance = this;
  }

  /**
   * 初始化 WebSocket 连接
   * @param {string} godotId - 要连接的 Godot 实例 ID
   * @param {Object} options - 配置选项
   */
  initialize(godotId, options = {}) {
    this.config = { ...options };
    this.config.godotId = godotId;
    this.connect();
  }

  /**
   * 建立 WebSocket 连接
   */
  connect() {
    if (this.ws && this.ws.readyState === WebSocket.OPEN) {
      console.warn("WebSocket connection already established");
      return;
    }

    try {
      const url = `${this.config.serverUrl}?type=frontend&godotId=${this.config.godotId}`;
      this.ws = new WebSocket(url);

      this.setupEventHandlers();
    } catch (error) {
      console.error("Failed to create WebSocket connection:", error);
      this.emit("error", {
        type: "connection_error",
        message: "Failed to create WebSocket connection",
        error: error.message,
      });
    }
  }

  /**
   * 设置 WebSocket 事件处理器
   */
  setupEventHandlers() {
    this.ws.onopen = (event) => {
      console.log("WebSocket connection established");
      this.isConnected = true;
      this.reconnectAttempts = 0;
      this.emit("connected", {
        godotId: this.config.godotId,
        timestamp: Date.now(),
      });
    };

    this.ws.onmessage = (event) => {
      try {
        const message = JSON.parse(event.data);
        this.handleMessage(message);
      } catch (error) {
        console.error("Error parsing message:", error);
        this.emit("error", {
          type: "message_parse_error",
          message: "Failed to parse incoming message",
          data: event.data,
          error: error.message,
        });
      }
    };

    this.ws.onclose = (event) => {
      console.log("WebSocket connection closed:", event.code, event.reason);
      this.isConnected = false;

      this.emit("disconnected", {
        code: event.code,
        reason: event.reason,
        wasClean: event.wasClean,
        timestamp: Date.now(),
      });

      // 自动重连逻辑
      if (
        this.config.autoReconnect &&
        this.reconnectAttempts < this.maxReconnectAttempts &&
        event.code !== 1000
      ) {
        // 正常关闭不重连
        this.scheduleReconnect();
      }
    };

    this.ws.onerror = (error) => {
      console.error("WebSocket error:", error);
      this.emit("error", {
        type: "websocket_error",
        message: "WebSocket connection error",
        error: error,
      });
    };
  }

  /**
   * 处理接收到的消息
   * @param {Object} message - 消息对象
   */
  handleMessage(message) {
    const { type, ...data } = message;

    // 首先触发通用消息事件
    this.emit("message", { type, ...data });

    // 然后触发特定类型的事件
    if (type) {
      this.emit(type, data);
    }
  }

  /**
   * 发送消息到 Godot 实例
   * @param {string} type - 消息类型
   * @param {Object} data - 消息数据
   */
  send(type, data = {}) {
    if (!this.isConnected || this.ws.readyState !== WebSocket.OPEN) {
      this.emit("error", {
        type: "send_error",
        message: "Cannot send message - WebSocket not connected",
        attemptedMessage: { type, data },
      });
      return false;
    }

    try {
      const message = {
        type,
        ...data,
        timestamp: Date.now(),
      };

      this.ws.send(JSON.stringify(message));
      this.emit("message_sent", message);
      return true;
    } catch (error) {
      console.error("Error sending message:", error);
      this.emit("error", {
        type: "send_error",
        message: "Failed to send message",
        attemptedMessage: { type, data },
        error: error.message,
      });
      return false;
    }
  }

  /**
   * 添加事件监听器
   * @param {string} eventType - 事件类型
   * @param {Function} callback - 回调函数
   * @param {Object} options - 选项
   */
  addListener(eventType, callback, options = {}) {
    if (typeof callback !== "function") {
      throw new Error("Callback must be a function");
    }

    if (!this.eventListeners.has(eventType)) {
      this.eventListeners.set(eventType, []);
    }

    const listeners = this.eventListeners.get(eventType);
    listeners.push({
      callback,
      once: options.once || false,
    });

    // 返回移除函数
    return () => {
      this.removeListener(eventType, callback);
    };
  }

  /**
   * 添加一次性事件监听器
   * @param {string} eventType - 事件类型
   * @param {Function} callback - 回调函数
   */
  once(eventType, callback) {
    return this.addListener(eventType, callback, { once: true });
  }

  /**
   * 移除事件监听器
   * @param {string} eventType - 事件类型
   * @param {Function} callback - 要移除的回调函数
   */
  removeListener(eventType, callback) {
    if (!this.eventListeners.has(eventType)) {
      return;
    }

    const listeners = this.eventListeners.get(eventType);
    const filteredListeners = listeners.filter(
      (listener) => listener.callback !== callback
    );

    if (filteredListeners.length === 0) {
      this.eventListeners.delete(eventType);
    } else {
      this.eventListeners.set(eventType, filteredListeners);
    }
  }

  /**
   * 移除特定事件的所有监听器
   * @param {string} eventType - 事件类型
   */
  removeAllListeners(eventType) {
    this.eventListeners.delete(eventType);
  }

  /**
   * 触发事件
   * @param {string} eventType - 事件类型
   * @param {Object} data - 事件数据
   */
  emit(eventType, data = {}) {
    if (!this.eventListeners.has(eventType)) {
      return;
    }

    const listeners = [...this.eventListeners.get(eventType)];
    const event = {
      type: eventType,
      ...data,
      timestamp: Date.now(),
    };

    // 执行监听器，并移除一次性监听器
    for (let i = 0; i < listeners.length; i++) {
      const listener = listeners[i];
      try {
        listener.callback(event);
      } catch (error) {
        console.error(`Error in event listener for "${eventType}":`, error);
      }

      if (listener.once) {
        this.removeListener(eventType, listener.callback);
      }
    }
  }

  /**
   * 安排重连
   */
  scheduleReconnect() {
    this.reconnectAttempts++;
    const delay =
      this.reconnectInterval * Math.pow(1.5, this.reconnectAttempts - 1);

    console.log(
      `Scheduling reconnect attempt ${this.reconnectAttempts} in ${delay}ms`
    );

    this.emit("reconnecting", {
      attempt: this.reconnectAttempts,
      maxAttempts: this.maxReconnectAttempts,
      delay: delay,
    });

    setTimeout(() => {
      if (!this.isConnected) {
        this.connect();
      }
    }, delay);
  }

  /**
   * 关闭连接
   */
  disconnect() {
    this.config.autoReconnect = false;

    if (this.ws) {
      this.ws.close(1000, "Manual disconnect");
    }
  }

  /**
   * 获取连接状态
   */
  getStatus() {
    return {
      isConnected: this.isConnected,
      godotId: this.config.godotId,
      reconnectAttempts: this.reconnectAttempts,
      readyState: this.ws ? this.ws.readyState : WebSocket.CLOSED,
    };
  }

  /**
   * 销毁实例
   */
  destroy() {
    this.disconnect();
    this.eventListeners.clear();
    this.ws = null;
    GodotWebSocketClient.instance = null;
  }
}

// 创建单例实例
const godotWebSocketClient = new GodotWebSocketClient();

// 防止修改单例实例
// Object.freeze(godotWebSocketClient);

export default godotWebSocketClient;
